import javax.swing.plaf.TableHeaderUI;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: 23735
 * Date: 2022-11-02
 * Time: 19:38
 */
public class TcpEchoServer {
    public ServerSocket serverSocket;//专门用来接受请求并建立链接
    public Socket clientSocket;//专门用来处理请求
    public TcpEchoServer(int port) throws IOException {
        this.serverSocket=new ServerSocket(port);
    }

    public void start() throws IOException {
        System.out.println("服务器启动!");
        //也可以利用线程池
        ExecutorService threadsPool=Executors.newCachedThreadPool();
        while(true){
            //接受请求
            clientSocket=serverSocket.accept();
//            //利用多线程才能让服务器同时处理多个客户端的请求
//            Thread t=new Thread(()->{
//                //建立链接并处理请求
//                try {
//                    createConnection(clientSocket);
//                } catch (IOException e) {
//                    throw new RuntimeException(e);
//                }
//            });
//            t.start();
            //创建线程池相对于每次创建一个线程来说效率更高一些
            threadsPool.submit(()->{
                try {
                    createConnection(clientSocket);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }

    public void createConnection(Socket clientSocket) throws IOException {
        System.out.printf("[%s:%d]建立链接成功\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
        //三个步骤
        //1.读取客户端请求(根据打开的文件流确定了读取的是客户端发来的请求)
        //这里针对TCP的读写和对于文件的读写是一摸一样的
        //利用socket构造文件流
        try(InputStream inputStream=clientSocket.getInputStream()){//注意打开的流
            //直接利用scanner读取(利用原生的InputStream也是可以的,但Scanner更方便)
            Scanner scanner=new Scanner(inputStream);
            try(OutputStream outputStream=clientSocket.getOutputStream()){//注意打开的流
                while(true){
                    if(!scanner.hasNext()){
                        System.out.printf("[%s:%d]断开链接\n",clientSocket.getInetAddress().toString(),clientSocket.getPort());
                        break;
                    }
                    //读取请求(TCP以字符流进行传输)
                    String request=scanner.next();
                    //2.根据请求计算响应
                    String response=process(request);
                    //3.返回响应(根据打开的文件流决定了是往客户端返回请求)
                    //为了方便用PrintWriter对OutputStream进行包裹
                    PrintWriter printWriter=new PrintWriter(outputStream);
                    printWriter.println(response);
                    printWriter.flush();
                    System.out.printf("[%d][req:%s resp:%s]\n",clientSocket.getPort(),request,response);
                }
            }
        }finally {
            clientSocket.close();//记得及时关闭
        }
    }

    public String process(String request){
        return request;
    }

    public static void main(String[] args) throws IOException {
        TcpEchoServer tcpEchoServer=new TcpEchoServer(9090);
        tcpEchoServer.start();
    }
}
